package com.jd.jobkeeper.utils.net;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.List;

public final class NetUtils {

    private static final Logger LOG = LoggerFactory.getLogger(NetUtils.class);

    /**
     * find properly address
     *
     * @return {@link InetAddress}
     */
    public static InetAddress findFirstNonLoopbackAddress(boolean siteLocalAddress,
                                                          List<String> preferredNetworks) {
        InetAddress result = null;

        try {
            int lowest = Integer.MAX_VALUE;
            for (Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces();
                 nics.hasMoreElements(); ) {
                NetworkInterface ifc = nics.nextElement();
                if (ifc.isUp()) {
                    LOG.debug("Testing interface: " + ifc.getDisplayName());
                    if (ifc.getIndex() < lowest || result == null) {
                        lowest = ifc.getIndex();
                    } else {
                        continue;
                    }
                    for (Enumeration<InetAddress> addrs = ifc.getInetAddresses(); addrs.hasMoreElements(); ) {
                        InetAddress address = addrs.nextElement();
                        if (address instanceof Inet4Address && !address.isLoopbackAddress()
                                && isPreferredAddress(address, siteLocalAddress, preferredNetworks)) {
                            LOG.debug("Found non-loopback interface: " + ifc.getDisplayName());
                            result = address;
                        }
                    }
                }
            }
        } catch (IOException ex) {
            LOG.error("Cannot get first non-loopback address", ex);
        }

        if (result != null) {
            return result;
        }

        try {
            return InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            LOG.warn("Unable to retrieve localhost");
        }

        return null;
    }


    private static boolean isPreferredAddress(InetAddress address, boolean siteLocalAddress,
                                              List<String> preferredNetworks) {
        if (siteLocalAddress) {
            final boolean isSiteLocalAddress = address.isSiteLocalAddress();
            if (!isSiteLocalAddress) {
                LOG.debug("Ignoring address: " + address.getHostAddress());
            }
            return isSiteLocalAddress;
        }
        if (preferredNetworks == null || preferredNetworks.isEmpty()) {
            return true;
        }
        for (String regex : preferredNetworks) {
            final String hostAddress = address.getHostAddress();
            if (hostAddress.matches(regex) || hostAddress.startsWith(regex)) {
                return true;
            }
        }

        return false;
    }


}
